// vscode当前编辑的区域，微软开源的代码编辑器的js项目
import {
  defineComponent,
  ref,
  onMounted,
  watch,
  onBeforeUnmount,
  shallowRef,
  PropType,
} from 'vue'

import * as Monaco from 'monaco-editor'

import { createUseStyles } from 'vue-jss'

const useStyles = createUseStyles({
  container: {
    border: '1px solid #eee',
    display: 'flex',
    flexDirection: 'column',
    borderRadius: 5,
  },
  title: {
    backgroundColor: '#eee',
    padding: '10px 0',
    paddingLeft: 20,
  },
  code: { flexGrow: 1 },
})

export default defineComponent({
  props: {
    code: {
      type: String as PropType<string>,
      required: true,
    },
    onChange: {
      type: Function as PropType<
        (value: string, event: Monaco.editor.IModelContentChangedEvent) => void
      >,
      required: true,
    },
    //会显示的区域
    title: {
      type: String as PropType<string>,
      required: true,
    },
  },
  setup(props) {
    // 需要一个shallowRef: 只监听value，不关心实际对象
    const editorRef = shallowRef()
    // 需要生成编辑器的Dom
    const containerRef = ref()

    let _subscription: Monaco.IDisposable | undefined
    let __prevent_trigger_change_event = false

    onMounted(() => {
      //组件初始化时创建一个Monaco的编辑器实例
      const editor = (editorRef.value = Monaco.editor.create(
        containerRef.value,
        {
          value: props.code, // 初始值
          language: 'json', // 代码生成语言
          formatOnPaste: true, // 当粘贴的时候自动进行一次格式化代码
          tabSize: 2, // tab缩进长度
          minimap: {
            enabled: false, // 不需要小的缩略图
          },
        },
      ))
      //根据代码的变化实时返回给组件使用的地方
      // 如果代码有变化，会在这里监听到，当受到外部数据改变时，不需要触发change事件
      _subscription = editor.onDidChangeModelContent((event) => {
        console.log('-------->', __prevent_trigger_change_event)
        if (!__prevent_trigger_change_event) {
          props.onChange(editor.getValue(), event)
        }
      })
    })

    onBeforeUnmount(() => {
      // 组件销毁时卸载编辑器
      if (_subscription) _subscription.dispose()
    })

    watch(
      () => props.code,
      (v) => {
        const editor = editorRef.value
        // 获取编辑器的textModel文本
        const model = editor.getModel()

        // 如果代码发生变化 这里需要更新一版
        if (v !== model.getValue()) {
          // 这是进行一次常规化的操作 文档原文：Push an "undo stop" in the undo-redo stack.
          editor.pushUndoStop()
          __prevent_trigger_change_event = true
          /**
           * @function 开始编辑编辑器, 文档原文：Push edit operations, basically editing the model. This is the preferred way of editing the model. The edit operations will land on the undo stack.
           * @param 编辑操作之前的光标状态。调用撤销或重做时，将返回此光标状态
           * @param 需要编辑的内容 range: 编辑的内容范围，这里选择的是全部范围
           * @param 在编辑器质性完成之后可以计算光标状态的一个回调参数
           */
          model.pushEditOperations(
            [],
            [
              {
                range: model.getFullModelRange(),
                text: v,
              },
            ],
            () => null,
          )
          editor.pushUndoStop()
          __prevent_trigger_change_event = false
        }
      },
    )

    const classesRef = useStyles()
    return () => {
      const classes = classesRef.value

      return (
        <div class={classes.container}>
          <div class={classes.title}>
            <span>{props.title}</span>
          </div>
          <div class={classes.container} ref={containerRef}></div>
        </div>
      )
    }
  },
})
